#include <iostream>
#include <memory>
#include <functional>

#include "TcpServer.hpp"
#include "Socket.hpp"
#include "InetAddr.hpp"
#include "CalCulate.hpp"
#include <signal.h>

using namespace socket_ns;
using callback_t = std::function<Response(const Request &req)>;

class Service
{
public:
    Service(callback_t cb)
        : _cb(cb)
    {}

    void ServiceHelper(socket_sptr sockptr, InetAddr client)
    {
        int sockfd = sockptr->SockFd();
        LOG(DEBUG, "get a new link %s:%d", client.Ip().c_str(), client.Port());
        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]# ";
        std::string inbuffer;

        while (true)
        {
            sleep(5);
            // 1.保证是完整的request，有效载荷长度
            Request req;

            int n = sockptr->Recv(&inbuffer);
            if (n == 0)
            {
                std::cout<<"收到关闭通知!\n";
                break;
            }
            else if(n<0)
            {
                std::cout<<"读取出错了!\n";
                break;
            }

            // 2.分析数据确认报文
            std::string package;
            while(true)
            {
                sleep(1);
                // std::cout << "inbuffer: " << inbuffer << std::endl;
                std::cout<<"处理!!\n";
                package = Decode(inbuffer);
                if(package.empty()) break;
                // std::cout << "-------------begin-----------------" << std::endl;
                // std::cout << "req string:\n" << package << std::endl;
                // 3.反序列化
                req.Deserialize(package);
                // 4.业务处理
                Response resp = _cb(req);
                // 5.对应答做序列化
                std::string send_str;
                resp.Serialize(&send_str);
                // std::cout << "resp Serialize:" << std::endl;
                // std::cout << send_str << std::endl;
                // 6.添加长度报头
                send_str = Encode(send_str);
                // std::cout << "resp Encode:" << std::endl;
                // std::cout << send_str << std::endl;
                
                //这个问题就是你向一个已经关闭的文件描述符中写入数据而导致的问题
                //在这里，你对端都已经关闭了，你还在写入数据
                int ret = sockptr->Send(send_str);
                if(ret <= 0)
                {
                    std::cout<<"关闭!!!\n";
                    break;
                }
            }
        }
    }

private:
    callback_t _cb;
};

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << "local_port" << std::endl;
}

int main(int argc, char *argv[])
{
    signal(SIGPIPE,SIG_IGN);
    if(argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    uint16_t port = std::stoi(argv[1]);

    Calculate cal;
    Service calservice(std::bind(&Calculate::Excute, &cal, std::placeholders::_1));
    io_server_t service = std::bind(&Service::ServiceHelper, &calservice, std::placeholders::_1, std::placeholders::_2);
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);

    tsvr->Loop();

    return 0;
}